﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Xml.Serialization;
using Clock.Properties;

namespace Clock.Utils
{
    public static class Skins
    {
        private static Lazy<Skin> _default = null;
        private static IDictionary<string, Lazy<Skin>> _skins = new Dictionary<string, Lazy<Skin>>();

        static Skins()
        {
            Skins._default = new Lazy<Skin>(() => new Skin()
            {
                CenterPoint = new Point(249, 249),
                BackImage = Resources.back,
                H = new ImgCfg()
                {
                    Image = Resources.h,
                    Center = new Point(-8, -123),
                    Angle = 0
                },
                M = new ImgCfg()
                {
                    Image = Resources.m,
                    Center = new Point(-8, -191),
                    Angle = 0
                },
                S = new ImgCfg()
                {
                    Image = Resources.s,
                    Center = new Point(-4, -193),
                    Angle = 0
                }
            });

            var skinDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Skins");

            if (Directory.Exists(skinDir))
            {
                foreach (var file in Directory.GetFiles(skinDir))
                {
                    if (string.Compare(Path.GetExtension(file), ".zip", true) != 0)
                    {
                        continue;
                    }

                    var skinName = Path.GetFileNameWithoutExtension(file);

                    Skins._skins[skinName] = new Lazy<Skin>(() => Skins.ReadZipFile(file));
                }
            }
        }

        public sealed class SKIN
        {
            public XY CenterPoint { get; set; }

            public string BackImage { get; set; }

            public POINTER H { get; set; }

            public POINTER M { get; set; }

            public POINTER S { get; set; }
        }

        public sealed class XY
        {
            public int X { get; set; }

            public int Y { get; set; }
        }

        public sealed class POINTER
        {
            public string Image { get; set; }

            public XY Center { get; set; }

            public int Angle { get; set; }
        }

        private static Skin ReadZipFile(string file)
        {
            try
            {
                using (var zip = ZipFile.OpenRead(file))
                {
                    var settingsEntry = zip.GetEntry("settings.xml");

                    if (settingsEntry == null)
                    {
                        return null;
                    }

                    using (var reader = new StreamReader(settingsEntry.Open()))
                    {
                        var skin_info = new XmlSerializer(typeof(SKIN)).Deserialize(reader) as SKIN;

                        var backImage_Entry = zip.GetEntry(skin_info.BackImage);

                        if (backImage_Entry == null)
                        {
                            return null;
                        }

                        var h_Entry = zip.GetEntry(skin_info.H.Image);

                        if (h_Entry == null)
                        {
                            return null;
                        }

                        var m_Entry = zip.GetEntry(skin_info.M.Image);

                        if (m_Entry == null)
                        {
                            return null;
                        }

                        var s_Entry = zip.GetEntry(skin_info.S.Image);

                        if (s_Entry == null)
                        {
                            return null;
                        }

                        return new Skin(Path.GetFileNameWithoutExtension(file))
                        {
                            BackImage = new Bitmap(backImage_Entry.Open()),
                            CenterPoint = new Point(skin_info.CenterPoint.X, skin_info.CenterPoint.Y),
                            H = new ImgCfg()
                            {
                                Angle = skin_info.H.Angle,
                                Center = new Point(skin_info.H.Center.X, skin_info.H.Center.Y),
                                Image = new Bitmap(h_Entry.Open())
                            },
                            M = new ImgCfg()
                            {
                                Angle = skin_info.M.Angle,
                                Center = new Point(skin_info.M.Center.X, skin_info.M.Center.Y),
                                Image = new Bitmap(m_Entry.Open())
                            },
                            S = new ImgCfg()
                            {
                                Angle = skin_info.S.Angle,
                                Center = new Point(skin_info.S.Center.X, skin_info.S.Center.Y),
                                Image = new Bitmap(s_Entry.Open())
                            }
                        };
                    }
                }
            }
            catch
            {
                return null;
            }
        }

        public static Lazy<Skin> Default => Skins._default;

        public static IList<string> AllSkinNames => Skins._skins.Keys.ToList();

        public static Skin GetSkinByName(string name)
        {
            if (!string.IsNullOrWhiteSpace(name))
            {
                if (Skins._skins.TryGetValue(name, out var skin))
                {
                    return skin.Value;
                }
            }

            return null;
        }
    }

    public sealed class Skin
    {
        public Skin(string name = null)
        {
            this.Name = name ?? string.Empty;
        }

        public string Name { get; }

        public Point CenterPoint { get; set; }

        public Bitmap BackImage { get; set; }

        public ImgCfg H { get; set; }

        public ImgCfg M { get; set; }

        public ImgCfg S { get; set; }
    }

    public sealed class ImgCfg
    {
        public Bitmap Image { get; set; }

        public Point Center { get; set; }

        public int Angle { get; set; }
    }
}